package org.jeecg.common.util;


import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 *
 * <h1>函数式招式工具类</h1>
 * <p>
 * 常用的一些操作进行封装，开箱即用
 *
 *
 * </p>
 *
 * @author songyafei
 * @date 2022-3-18
 */
public class FunctionUtil {

    /**
     * 用来获取一个泛型参数指定类型的对象数据。
     * @param supplier
     * @param <T>
     * @return
     */
    public static <T> T supplier(@NotNull Supplier<T> supplier){
        return supplier.get();
    }


    /**
     *   Function 使用 获取一组对象中的某个属性，或者 属性增强处理
     * @param list
     * @param f
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> map(List<T> list,@NotNull Function<T, R> f) {
        List<R> result = new ArrayList<>();
        for(T s: list){
            result.add(f.apply(s));
        }
        return result;
    }

    /**
     * 过滤集合
     * @param list
     * @param p
     * @param <T>
     * @return List<T>
     */
    public static <T> List<T> filterList(List<T> list,@NotNull Predicate<T> p){
        List<T> result = new ArrayList<>();
        for(T e: list){
            if(p.test(e)){
                result.add(e);
            }
        }
        return result;
    }

    /**
     *  传入集合对每一个对象做操作
     *   场景分析： 当需要一次对一个对象中的属性做业务单独处理时可以使用
     * @param list
     * @param c
     * @param <T>
     */
    public static <T> void getT(List<T> list,@NotNull Consumer<T> c){
        list.forEach(i -> c.accept(i));
    }

    /**
     *  传入两个list进行处理后返回一个list
     * @param l1
     * @param l2
     * @param biFunction
     * @param <T>
     * @return T
     */
    public static <T> T calList(List<T> l1, List<T> l2,@NotNull BiFunction<List<T>,List<T>,List<T>> biFunction){
        return (T) biFunction.apply(l1,l2);
    }

    /**
     * 对比localDate 日期
     * @param d1
     * @param d2
     * @param biPredicate
     * @return boolean
     */
    public static boolean calLocalDate(LocalDate d1, LocalDate d2,@NotNull BiPredicate<LocalDate,LocalDate> biPredicate){
        return biPredicate.test(d1,d2);
    }

    /**
     * 传入两个同类型的集合做处理
     * @param l1
     * @param l2
     * @param binaryOperator
     * @param <T>
     * @return List<T>
     */
    public static <T> List<T> calList(List<T> l1, List<T> l2,@NotNull BinaryOperator<List<T>> binaryOperator){
        return  binaryOperator.apply(l1,l2);
    }

    /**
     *  传入两个同类型的字符串做处理
     * @param s1
     * @param s2
     * @param binaryOperator
     * @return String
     */
    public static String calString(String s1,String s2,@NotNull BinaryOperator<String> binaryOperator){
        return binaryOperator.apply(s1,s2);
    }

    /**
     * 对集合为true 做处理
     * @param list
     * @param booleanSupplier
     * @return Boolean
     */
    public static Boolean calList(List<?> list,@NotNull BooleanSupplier booleanSupplier){
        return booleanSupplier.getAsBoolean();
    }

    /**
     * 比较两个任意类型做比较
     * @param o1
     * @param o2
     * @param binaryOperator
     * @param <T>
     * @return T
     */
    public static <T>  T calSort(Object o1,Object o2,@NotNull BinaryOperator<Object> binaryOperator){
        return (T) binaryOperator.apply(o1,o2);
    }

    /**
     * <h2>处理List函数式接口</h2>
     * <h3>针对任意List数据进行消费，但没有返回值</h3>
     * <p>
     * 案例：
     * List<String> list = new ArrayList<String>(10);</b>
     * JtUtil.dealList(list,i->{
     * //对集合进行操作
     * });
     * </p>
     *
     * @param list     列表
     * @param consumer 消费者
     * @throws Exception 异常
     */
    public static <T> void parseList(List<T> list, @NotNull Consumer<List<T>> consumer) throws Exception {
        consumer.accept(list);
    }


    /**
     * <h2>处理List函数式接口</h2>
     * <h3>针对任意List数据进行消费，带boolean返回值</h3>
     * <p>
     * 案例：
     * List<String> list = new ArrayList<String>(10);</b>
     * boolean addCheck = JtUtil.dealList(list,i->{
     * return  userService.save(i);
     * });
     * </p>
     *
     * @param list      列表
     * @param predicate 消费者
     * @return boolean
     * @throws Exception 异常
     */
    public static <T> boolean resultAfterProcessing(List<T> list, @NotNull Predicate<List<T>> predicate) throws Exception {
        return predicate.test(list);
    }



    /**
     * <h2>处理两个List函数式接口</h2>
     * <h3>针对两个List数据处理并返回结果</h3>
     * <p>
     * 案例：
     *         List<Integer> l1 = new ArrayList<>(Arrays.asList(1, 2, 3, 5, 6));
     *         List<Integer> l2 = new ArrayList<>(Arrays.asList(11, 22, 33, 55, 66));
     *         List<Integer> l3 = new ArrayList<>();
     *
     *         List<Integer> result = twoValueCal(l1, l2, (i1, i2) -> {
     *             i1.forEach(j -> {
     *                 i2.forEach(j2 -> {
     *                     l3.add((j + j2) * 2);
     *                 });
     *             });
     *             return l3;
     *         });
     *
     * </p>
     *
     * @param l1           列表1
     * @param l2           列表2
     * @param binaryOperator 函数式
     * @return boolean
     * @throws Exception 异常
     * @See {@link BinaryOperator}
     */
    public static <T> List<T> twoValueCal(List<T> l1, List<T> l2, @NotNull BinaryOperator<List<T>> binaryOperator) {
        return binaryOperator.apply(l1, l2);
    }



    /**
     * <h2>处理单个List并返回结果函数式接口</h2>
     * <h3>针对List数据处理不需要入参并返回结果</h3>
     * <p>
     * 案例：
     *         List<Integer> result = new ArrayList<>(Arrays.asList(24,46,68,112,134,26,48,70,114,136,28,50,72,116,138,32,54,76,120,142,34,56,78,122,144));
     *         List<Integer> integers = parseList(() -> {
     *             Integer max = result.stream().filter(i->i>200000).max(Comparator.comparing(Integer::intValue).reversed())
     *                     .orElseGet(()->result.stream().mapToInt(Integer::intValue).sum());
     *             Integer min = result.stream().min(Comparator.comparing(Integer::intValue))
     *                     .orElseGet(()-> result.stream().filter(i->i>100).findFirst().get());
     *             return Arrays.asList(max,min);
     *         });
     *         System.out.println(integers);
     *
     * </p>
     *
     * @param supplier 函数式
     * @return boolean
     * @throws Exception 异常
     * @See {@link Supplier}
     */
    public static <T> List<T> parseList(@NotNull Supplier<List<T>> supplier){
        return supplier.get();
    }



}
